/**
 * Copyright 2014-2020 the original author or authors.
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.upb.webserver.shell;

import com.upb.webserver.common.constant.Constant;
import com.upb.webserver.common.enums.ScpTypeEnum;
import com.upb.webserver.common.exception.WebServerException;
import com.upb.webserver.common.properties.WebServerProperties;
import com.upb.webserver.common.returncode.ConstantCode;
import com.upb.webserver.common.tools.JsonUtils;
import com.upb.webserver.common.tools.SshTools;
import com.upb.webserver.common.tools.cmd.ExecuteResult;
import com.upb.webserver.common.tools.cmd.JavaCommandExecutor;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.nio.file.Files;
import java.nio.file.Paths;

/**
 * Java call shell script and system command.
 */
@Log4j2
@Component
public class ShellService {

    @Autowired
    private WebServerProperties webServerProperties;

    /**
     * @param typeEnum
     * @param sshUser
     * @param ip
     * @param sshPort
     * @param src
     * @param dst
     * @return
     */
    public void scp(ScpTypeEnum typeEnum, String sshUser, String ip, int sshPort, String src, String dst) {
        if (typeEnum == ScpTypeEnum.UP) {
            // scp files to remote
            if (Files.isRegularFile(Paths.get(src))) {
                // if src is file, create parent directory of dst on remote
                String parentOnRemote = Paths.get(dst).getParent().toAbsolutePath().toString();
                SshTools.createDirOnRemote(ip, parentOnRemote, sshUser, sshPort, webServerProperties.getSshPrivateKey());
            }
            if (Files.isDirectory(Paths.get(src))) {
                // if src is directory, create dst on remote
                SshTools.createDirOnRemote(ip, dst, sshUser, sshPort, webServerProperties.getSshPrivateKey());
            }
        }

        String command = String.format("bash -x -e %s -t %s -i %s -u %s -p %s -r %s -s %s -d %s",
                Constant.SCP_SHELL, typeEnum.getValue(), ip, sshUser, sshPort, webServerProperties.getSshPrivateKey(), src, dst);
        log.info("exec file send command: [{}]", command);
        ExecuteResult result = JavaCommandExecutor.executeCommand(command, Constant.EXEC_HOST_INIT_TIMEOUT);

        if (result.failed()) {
            log.error("Send files from [{}] to [{}:{}] failed.", src, ip, dst);
            throw new WebServerException(ConstantCode.TRANSFER_FILES_ERROR.msg(result.getExecuteOut()));
        }
    }


    /**
     * @param ip     Required.
     * @param port   Default 22.
     * @param user   Default root.
     * @param pwd    Not required.
     * @param method exec method：checkHost、checkWebaseImages、checkFabricImages
     * @return
     */
    public ExecuteResult execHostOperate(String ip, int port, String user, String pwd, String method) {
        log.info("Exec execHostOperate method for [{}@{}:{}]", user, ip, port);

        int newport = port <= 0 || port > 65535 ? SshTools.DEFAULT_SSH_PORT : port;
        String newUser = StringUtils.isBlank(user) ? SshTools.DEFAULT_SSH_USER : user;
        String passwordParam = StringUtils.isBlank(pwd) ? "" : String.format(" -p %s ", pwd);

        String command = String.format("bash -x -e %s -H %s -P %s -u %s %s -r %s -m %s ",
                Constant.SHELL_HOST_OPERATE, ip, newport, newUser, passwordParam, webServerProperties.getSshPrivateKey(), method);

        ExecuteResult result = JavaCommandExecutor.executeCommand(command, Constant.EXEC_HOST_INIT_TIMEOUT);
        log.info("finish execHostOperate method for [{}@{}:{}] result:{}", user, ip, port, JsonUtils.objToString(result));
        return result;
    }
}